#include "game.h"

Game::Game ()
{
	generate_objects();	
	generate_map();
}


void Game::generate_map()
{
	_map.setBitmap();
	_map.generate_default_map();
}

void Game::generate_objects()
{
	_digdug = Movables(DIGDUG, game_grid_elements/2, game_grid_elements/2); 
	_monsters.push_back(Movables(MONSTER,  game_grid_elements/2-6, game_grid_elements/2 -10));
	_monsters.push_back(Movables(MONSTER,  game_grid_elements/2-6, game_grid_elements/2 +6));
}

bool Game::update(Action instruction)
{
//Handle Digdug's action first;
//Digdug is always the first object in the vector of movables contained in game
	Move_result result = HAS_MOVED; 

	if(instruction != SHOOT && instruction != NONE)
	{
		//convert enum type instruction to direction
		Direction dir = static_cast<Direction>(instruction);
		
		if(move(_digdug, dir) ==GAME_OVER)
		{return false;} 

		if(move(_monsters.at(0), DOWN)==GAME_OVER)
		{return false;}
		if(move(_monsters.at(1), UP)==GAME_OVER)
		{return false;}
	}

	if(instruction == SHOOT)
	{
		//!!projectile code here
	}

//Handle movement of all other movable objects
//start moving through vector containing movable objects of the game starting at the first object after digdug	
	//for(int monster_count = 0; monster_count != _monsters.size(); monster_count++)
	//{
	//	
	//	Direction dir = static_cast<Direction>(instruction);
	//		

	//		if(move(_monsters.at(monster_count), dir)==GAME_OVER)
	//		{return false; break;}
	//}

	return true;
//!!monsters projectile code


}

Rules Game::get_rule(Movable_type object_type, Movable_type map_location_type)
{
	if(map_location_type == HOLE)
	{
		return CAN_MOVE;
	}

	else if(map_location_type == SAND)
	{
		if(object_type == DIGDUG)
		{
			return CAN_MOVE;
		}
		else return CANT_MOVE;
	}

	else if(map_location_type == MONSTER)
	{
		switch(object_type)
		{
		case DIGDUG:
			return DEATH_TO_DIGDUG;
			break;
		case PROJECTILE:
			return DEATH_TO_MONSTER;
			break;
		case MONSTER:
			return CAN_OVERLAP;
			break;
		}
	}
	
	else if(map_location_type == OVERLAP)
	{
		switch(object_type)
		{
		case DIGDUG:
			return DEATH_TO_DIGDUG;
			break;
		case PROJECTILE:
			return DEATH_TO_MONSTER;
			break;
		case MONSTER:
			return CAN_MOVE;
			break;
		}
	}
	

//will only happen if trying to move a monster
	else if(map_location_type == PROJECTILE)
	{
		return DEATH_TO_MONSTER;
	}
	else if(map_location_type == DIGDUG)
	{
		return DEATH_TO_DIGDUG;
	}
	return CAN_MOVE;
}

Move_result Game::move(Movables& movable, Direction direction)
{

	Move_result result = HAS_MOVED;
// get the coordinates and dimensions of the movable
	int start_x = movable.x();
	int start_y = movable.y();
	int x = movable.x(); 
	int y = movable.y();
	int radius = movable.radius();
	int length = 2*radius + 1;
	int speed = movable.speed();


	int delta_x = 0;
	int delta_y = 0;
	int start_check_x = 0;
	int end_check_x = 0;
	int start_check_y = 0;
	int end_check_y = 0;
//increment is set to +1 or -1
//if moving left or up increment is set to -1 so that the element being checked decrements with each loop
//if moving right or down the element being checked is decremented with each loop  
	int increment = 1;

	switch(direction)
	{
case UP:
			delta_y = -1;
//checks from right to left
			start_check_x = start_x + radius;
			end_check_x = start_x - radius - 1;
			start_check_y = start_y - radius - 1;
			end_check_y = start_y - radius - speed - 1;
			increment = -1;

			break;

		case DOWN:
			delta_y = +1;
//checks from left to right
			start_check_x = start_x - radius;
			end_check_x = start_x + radius + 1;
			start_check_y = start_y + radius + 1;
			end_check_y = start_y + radius + speed +1;
			increment = 1;

			break;
		
		case LEFT:
			delta_x = -1;
			start_check_x = start_x - radius - 1;
			end_check_x = start_x - radius - speed - 1;
//checks from bottom to top
			start_check_y = start_y + radius;
			end_check_y = start_y - radius - 1;
			increment = -1;

			break;
		
		case RIGHT:
			delta_x = +1;
			start_check_x = start_x + radius + 1;
			end_check_x = start_x + radius + speed + 1;
//checks from top to bottom
			start_check_y = start_y - radius;
			end_check_y = start_y + radius + 1;
			increment = 1;
	}

	for (int i = start_check_x; i != end_check_x  && result == HAS_MOVED; i += delta_y + delta_x)
			{
				if (i < 0 || i == game_grid_elements)
				result = CANNOT_MOVE;
				
				for (int j = start_check_y; j != end_check_y && result == HAS_MOVED; j += delta_y + delta_x)
				{
					if(j < 0 || j == game_grid_elements )
						result = CANNOT_MOVE;
					else
					{
						switch(get_rule(movable.type(), _map.element(i, j)))
						{
						case CAN_MOVE:
							_map.set_type(movable.type(), i, j);
							if (_map.element(i - delta_x*length, j  -delta_y*length) == OVERLAP)
							_map.set_type(movable.type(), i -delta_x*length, j -delta_y*length);
							else
							_map.set_type(HOLE, i + -delta_x*length, j + -1*delta_y*length);
						
							movable.set_location(start_x + delta_x*(i-start_check_x +1), start_y + delta_y*(j-start_check_y +1));
						
							break;
						case CANT_MOVE:
							result = CANNOT_MOVE;
							break;
						case DEATH_TO_DIGDUG:
							result = GAME_OVER;
							break;
	//!!must finish writing this case to destroy projectile and specific monster
						case DEATH_TO_MONSTER:
							result = OBJECT_DEAD;
							break;
						case CAN_OVERLAP:
							_map.set_type(OVERLAP, i, j);
							_map.set_type(HOLE, i + -delta_x*length, j + -1*delta_y*length);
							movable.set_location(start_x + delta_x*(i-start_check_x +1), start_y + delta_y*(j-start_check_y +1));
						
							break;
						}
					}
					
				}
			}

		if(x == start_x && y == start_y && result != GAME_OVER)
		{
			result = CANNOT_MOVE;
		}
	
		
		return result;
}

Map Game::get_map()
{
	return _map;
}

Movables Game::get_movable (Movable_type type, int vector_count)
{
  switch (type)
  {
	  case DIGDUG:		return _digdug;							break;
	  case MONSTER:		return _monsters.at(vector_count);		break;
	  case PROJECTILE:	return _projectiles.at(vector_count);	break;
	  default:			return _digdug;							break;
	 // case ROCK:		return _rock.at(vector_count);			break;	
  }


}